MaxTypeLen = 100
HashSize = 4
MaxPar = 10
MaxFunctionLength  = 500
#typeSpecifier 

Int = 0
Char = 1
Float = 2
Double = 3
Long = 4
Void = 5

num_temporaries = 0
num_labels = 0

reserved_words = {
        'auto' : 'AUTO',
        'break': 'BREAK',
        'case':'CASE',
        'char' : 'CHAR',
        'const':'CONST',
        'continue':'CONTINUE',
        'default':'DEFAULT',
        'do' : 'DO',
        'double' : 'DOUBLE',
        'else':'ELSE',
        'enum':'ENUM',
        'extern':'EXTERN',
        'float':'FLOAT',
        'for':'FOR',
        'goto' : 'GOTO',
        'if':'IF',
        'int':'INT',
        'long':'LONG',
        'register' : 'REGISTER',
        'return' : 'RETURN',
        'short':'SHORT',
        'signed':'SIGNED',
        'sizeof':'SIZEOF',
        'static':'STATIC',
        'struct' : 'STRUCT',
        'switch' : 'SWITCH',
        'typedef':'TYPEDEF',
        'union':'UNION',
        'unsigned':'UNSIGNED',
        'void':'VOID',
        'volatile':'VOLATILE',
        'while':'WHILE'
}        

reserved_map = { }
for r in reserved_words:
      reserved_map[r.lower()] = r

class SymEntry:
      global MaxPar
      def __init__(self):
	    self.id = ""
	    self.scope = 0
	    self.type = 0
	    self.keywordval = 0 #//UNION, INT , etc.
	    self.linenum = 0
	    self.isPointer = 0
	    self.isArray = 0
	    self.ArrayLimit = 0
	    self.isFunction = 0
	    self.offset = 0
	    self.width = 0
	    self.numParameters = 0
	    self.ParameterList = []
	    for i in range(MaxPar):
		  temp = Attribute()
		  self.ParameterList.append(temp) 
	    #Will hold parameter List if the isFunction flag=1;	    
	    self.next = None



class Attribute:
      global MaxPar
      def __init__(self):
	    #self.type = ""
	    self.id = ""
	    self.type = 0
	    self.isArray = 0 	#// True if variable is array
	    self.ArrayLimit = 0 # upper limit of array (valid if DIMENSION is true)
	    self.width = 0
	    self.isPointer = 0
	    self.qualifier = 0
	    self.specifier = 0
	    self.storage = 0
	    self.scope = 0	#//ISKI ZARURAT HI KYA HAI AS IN ATTRIBUTES!!!!
	    self.IntConstValue = 0	# because this g++ compiler set 4 byte for long but we are setting 8 bytes
	    self.IntConst = 0
	    self.FloatConstValue = 0.0	# to store the value of double or float      
	    self.StringValue = ""
	    self.isFunction = 0
	    self.numParameters = 0
	    self.isString = 0
	    self.offset = 0
	    self.code = ""
	    self.icode = ""
	    self.ParameterList = []
	    for i in range(MaxPar):
		  temp = None
		  self.ParameterList.append(temp)
	    #Will hold parameter List if the isFunction flag=1;	

class VALUE:
      def __init__(self):
	    self.intValue = 0
	    self.longIntValue = 0
	    self.floatValue = 0.0
	    self.doubleValue = 0.0
	    self.charValue = ""
	    self.string = ""


class SymTableNode:
      global HashSize
      def __init__(self):
	    self.scope = 0
	    self.name = ""
	    self.table = []
	    for i in range(HashSize):
		  temp = SymEntry()
		  self.table.append(temp) 
	    self.next = None

# global name used in other places
global1 = []
for i in range(2):
      temp = SymTableNode()
      global1.append(temp) 

tail = []
for i in range(2):
      temp = SymTableNode()
      tail.append(temp) 

def CreateNewScopeTableNode():
      global HashSize
      t = ScopeTableNode()
      t.scope = 0
      t.next = None
      for i in range(HashSize):
	    t.table[i] = None
      return t

def Scopelookup(name):
      global HashSize
      r = ScopeEntry()
      s = ScopeEntry()
      r = None      # Check original code as r stands for both pointer and symentry
      temp = ScopeTableNode()
      temp = Global
      i = 0
      k = ord(name[0])%HashSize
      while temp.next != None:
	    s = temp.table[k]
	    if s!= None:
		  if s.id == name:
			r = s
		  else:
			while s.next != None:
			      s = s.next
			      if s.id == name:
				    r = s
				    break
	    temp = temp.next
      s=temp.table[k]  
      if s!= None:
	    if s.id  == name:
		  r = s
	    else:
		  while s.next != None:
			s = s.next
			if s.id == name:
			      r = s
			      break
      return r

def InsertScopeTable(name,currentScope,typ):
      global HashSize
      global Tail      
      if Tail.scope == None:
	    print "NewScope : ",currentScope," .\n"
	    Tail.scope = currentScope
      
      elif Tail.scope != currentScope:
	    print "NewScope : ",currentScope," .\n"
	    temp = ScopeTableNode()
	    temp = CreateNewScopeTableNode()
	    temp.scope = currentScope
	    Tail.next = temp
	    Tail = temp
      p = ScopeEntry()
      p.id=name
      p.scope = currentScope
      p.type = typ
      p.next = Tail.table[ord(name[0])%HashSize]
      Tail.table[ord(name[0])%HashSize] =  p 
      return p
      
def InitializeScopeTable():
      Global=CreateNewScopeTableNode()
      Tail=Global
      InsertScopeTable("ACA","GLOBAL","INT")
      InsertScopeTable("BCA","GLOBAL","INT1")
      InsertScopeTable("ACAa","GLOBALa","INTa")
      InsertScopeTable("ACa","GLOBALa","INTA")

def PopScope():
      global Tail
      temp = ScopeTableNode()
      temp = Global
      while temp.next.next != None:
	    temp = temp.next
      temp.next = None
      #free(Tail)
      Tail=temp 

# int INTEGER=50,KEYWORD=100;

def CreateNewSymTableNode():
      global HashSize
      t = SymTableNode()
      t.scope = 0
      t.next = None
      for i in range(HashSize):
	    t.table[i] = None
      return t

def lookup(name, FuncName):
      print "Inside lookup function"
      global HashSize
      global global1      
      r = SymEntry()
      s = SymEntry()
	# this was originally not commented
      r = None        # Check original code as r stands for both pointer and symentry
      temp = SymTableNode()
      print "name i.e, t[1] recieved by lookup function is "+name
      if name != None:
	    print "further since name is not null, inside if loop in lookup method"
	    #print "Error Check : "+name
	    k = ord(name[0])%HashSize
	    print "hash function value for "+name+" is "+str(k)+" and funcName is "+str(FuncName)
	    for a in range(FuncName+1):
		  print "Now looking for cat in Funcname = "+str(a)
		  temp = global1[a]
		  while temp.next != None:
			s = temp.table[k]
			if s!= None:
			      if s.id == name:
				    r = s
			      else:
				    while s.next != None:
					  s = s.next
					  if s.id == name:
						r = s
						break
			temp = temp.next
		  s = temp.table[k]			
		  if s!=None:
			if s.id == name:
			      r = s
			else:
			      while s.next != None:
				    s = s.next
				    if s.id == name:
					  r = s
					  break
   
      return r


def InsertSymTable(name,currentScope,typ,FuncName):
      global HashSize
      global tail      
      print "Inserting "+name+" into SymTable with current scope = "+str(currentScope)+" and Funcname  = "+str(FuncName)
      print "Value of tail[FuncName].scope is = "+str(tail[FuncName].scope)
      if tail[FuncName].scope!=currentScope:
	    #printf("NewScope : %d.\n",currentScope);
	    temp = SymTableNode()
	    temp = CreateNewSymTableNode()
	    temp.scope = currentScope
	    tail[FuncName].next=temp
	    tail[FuncName]=temp
      print "hash function value for "+name+" is "+str(ord(name[0])%HashSize)
      p = SymEntry()
      p.id = name
      p.scope=tail[FuncName].scope
      p.type = typ
      
      p.next=tail[FuncName].table[ord(name[0])%HashSize]
      tail[FuncName].table[ord(name[0])%HashSize]=p
      return p

def InitializeSymTable(KEYWORD):
      global MaxPar
      global tail
      global global1
      counter=0
      global1[0]=CreateNewSymTableNode()
      tail[0]=global1[0]
      global1[1]=CreateNewSymTableNode()
      tail[1]=global1[1]
      #global[1]->name=(char*)malloc(sizeof(char)*100);//Function name is assumed to be less than 100 for now.
      global1[0].name = "Global"
      p = SymEntry()    
      print "Global created.\n"

      p = InsertSymTable("break",0,KEYWORD,0)
      #p.keywordval=BREAK
      p=InsertSymTable("print_t",0,KEYWORD,0)
      #p.keywordval=0
      p.isFunction=1
      p.linenum=0
      p.type=400
      p.scope=0				             
      p.keywordval=0	#UNION, INT , etc.
      p.isPointer=0
      p.isArray=0
      p.ArrayLimit=0      
      p.offset=-1
      p.width=0
      p.numParameters=1
      p.ParameterList[0] = initAttr(p.ParameterList[0])
      p.ParameterList[0].type=400

      for counter in  range(MaxPar):
	    p.ParameterList[counter]=None

'''
      p=InsertSymTable("case",0,KEYWORD,0)
      #p.keywordval=CASE
      p=InsertSymTable("char",0,KEYWORD,0)
      #p.keywordval=CHAR
      p=InsertSymTable("const",0,KEYWORD,0)
      #p.keywordval=CONST
      p=InsertSymTable("continue",0,KEYWORD,0)
      #p.keywordval=CONTINUE
      p=InsertSymTable("default",0,KEYWORD,0)
      #p.keywordval=DEFAULT
      p=InsertSymTable("do",0,KEYWORD,0)
      #p.keywordval=DO
      p=InsertSymTable("double",0,KEYWORD,0)
      #p.keywordval=DOUBLE
      p=InsertSymTable("else",0,KEYWORD,0)
      #p.keywordval=ELSE
      p=InsertSymTable("enum",0,KEYWORD,0)
      #p.keywordval=ENUM
      p=InsertSymTable("extern",0,KEYWORD,0)
      #p.keywordval=EXTERN
      p=InsertSymTable("float",0,KEYWORD,0)
      #p.keywordval=FLOAT
      p=InsertSymTable("for",0,KEYWORD,0)
      #p.keywordval=FOR
      p=InsertSymTable("goto",0,KEYWORD,0)
      #p.keywordval=GOTO
      p=InsertSymTable("if",0,KEYWORD,0)
      #p.keywordval=IF
      p=InsertSymTable("int",0,KEYWORD,0)
      #p.keywordval=INT
      p=InsertSymTable("long",0,KEYWORD,0)
      #p.keywordval=LONG
      p=InsertSymTable("register",0,KEYWORD,0)
      #p.keywordval=REGISTER
      p=InsertSymTable("return",0,KEYWORD,0)
      #p.keywordval=RETURN
      p=InsertSymTable("short",0,KEYWORD,0)
      #p.keywordval=SHORT
      p=InsertSymTable("signed",0,KEYWORD,0)
      #p.keywordval=SIGNED
      p=InsertSymTable("sizeof",0,KEYWORD,0)
      #p.keywordval=SIZEOF
      p=InsertSymTable("static",0,KEYWORD,0)
      #p.keywordval=STATIC
      p=InsertSymTable("struct",0,KEYWORD,0)
      #p.keywordval=STRUCT
      p=InsertSymTable("switch",0,KEYWORD,0)
      #p.keywordval=SWITCH
      p=InsertSymTable("typedef",0,KEYWORD,0)
      #p.keywordval=TYPEDEF
      p=InsertSymTable("union",0,KEYWORD,0)
      #p.keywordval=UNION
      p=InsertSymTable("unsigned",0,KEYWORD,0)
      #p.keywordval=UNSIGNED
      p=InsertSymTable("void",0,KEYWORD,0)
      #p.keywordval=VOID
      p=InsertSymTable("volatile",0,KEYWORD,0)
      #p.keywordval=VOLATILE
      p=InsertSymTable("while",0,KEYWORD,0)
      #p.keywordval=WHILE
'''



def PrintAttribute(a):	
      print "\nInside PrintAttribute method\n"
      if(a==None):      
	    print "Attribute is not defined Yet\n"      
      else:      	    
	    print "\nAttribute ID : "
	    if(a.id!=None):	    
		  print a.id	    
	    print ",Type :"+a.type+" ,isArray :"+a.isArray+" ,ArrayLimit :"+a.ArrayLimit+" ,width :"+a.width+" ,"
	    print "isPointer :"+a.isPointer+" ,qualifier :"+a.qualifier+" ,specifier :"+a.specifier+" ,storage :"+a.storage+" ,"
	    print "scope :"+a.scope+" ,IntConstValue :"+a.IntConstValue+" ,IntConst :"+a.IntConst+" ,FloatConstValue :"+a.FloatConstValue+" ,"
	    
	    if(a.StringValue!=None):	    
		  print "StringValue : "+a.StringValue+" ,"	    
	    print "isFunction : "+a.isFunction+" ,numParameters "+a.numParameters+" ,isString : "+a.isString+" ,offset : "+a.offset+" ,"
	    if(a.code!=None):	    
		  print "Code :\n "+a.code+" \n"	    
	    if(a.code!=None):	    
		  print "Intermediate Code :\n "+a.icode+" \n"	    
	    print " Parameters :"
	    for i in range(a.numParameters):	    	    
		  print "Parameter "+(i+1)+"\n"
		  if(a.ParameterList[i]==None):	    
			break	   
	    PrintAttribute(a.ParameterList[i])	    
	    print " Attribute Printed \n"
	    
def PrintSymEntry(a):
        print "\nInside PrintSymEntry Method\n"
	if(a==None):	
	    print "SymEntry is not defined Yet\n"	
	else:		      
	      print "\nSymEntry ID : "
	      if(a.id!=None):	      
		    print a.id	      
	      print ",Type :"+str(a.type)+" ,isArray :"+str(a.isArray)+" ,ArrayLimit :"+str(a.ArrayLimit)+" ,width :"+str(a.width)+" ,"
	      print "isPointer :"+str(a.isPointer)+" ,"
	      print "scope :"+str(a.scope)+" ,"	      
	      print "isFunction : "+str(a.isFunction)+" ,numParameters "+str(a.numParameters)+" ,offset : "+str(a.offset)+" ,"
	      print " Parameters :"
	      for i in range(a.numParameters):
		  if(a.ParameterList[i]==None):		  
			break		  
		  print "Parameter "+str(i+1)+"\n"
		  PrintAttribute(a.ParameterList[i])	      
	      print " SymEntry Printed \n"	


def PrintSymTable():
      global HashSize
      global global1
      print "\nPrinting Symbol Table :\n"
      s = SymEntry();
      temp = SymTableNode()
      i = 0
      k = 0	#//Biggest Scope found less than or equal to internalScope.
      for k in range(2):	
	    print "\nLooking in Function Node ",k,"\n"
	    temp = global1[k]
	    while temp.next != None:
		  print "\nLooking in Node %d\n",temp.scope		 
		  for i in range(HashSize):
			s = temp.table[i]
			if s!= None:
			      PrintSymEntry(s)
			      while s.next != None:
				    s = s.next
				    PrintSymEntry(s)
			#printf("\n00000000000000000000000000000000000000000\n");
		  temp=temp.next
	    print "\nLooking in Node ",temp.scope,"\n"
	    for i in  range(HashSize):
		  s = temp.table[i]
		  if s!= None:
			PrintSymEntry(s)
			while s.next != None:
			      s = s.next
			      PrintSymEntry(s)
      #printf("\nSearch Finished\n");  

def CheckBeforeMerge(a1,a2):
      print "\nInside CheckBeforeMerge Method\n"
      test_file.write("\nInside CheckBeforeMerge Method\n")
      #For arithmatic operations
      flag=0
      #int, (char and notstring), long, short, float.double ke alava kuch ho to operation not valid.
      if(not((a1.specifier==2 and a1.isString==0)or(a1.specifier==4)or(a1.specifier==5)or(a1.specifier==6)or(a1.specifier==7)or(a1.qualifier==1 and a1.isString!=1))):
	    flag=1
      if(not((a2.specifier==2 and a2.isString==0)or(a2.specifier==4)or(a2.specifier==5)or(a2.specifier==6)or(a2.specifier==7)or(a1.qualifier==1 and a1.isString!=1))):      
	    flag=1      
      if(a1.isFunction==1 or (a1.isPointer==1) or a2.isFunction==1 or (a2.isPointer==1)):      
	    flag=1      
      test_file.write(str(flag)+"\n")
      return flag
      

def MergeAttributes3Code(a1,a2):
      print "\nInside MergeAttributes3Code Method\n"
      #For arithmatic operations
      a = Attribute()
      a.isArray=0
      a=initAttr(a)
      if((a1.specifier==4 or a1.specifier==5) and (a2.specifier==4 or a2.specifier==5)):      
	    a.specifier=a1.specifier
	    if(a2.specifier==5):      
		  a.specifier=5    
      elif((a1.specifier==4 or a1.specifier==5) and (a2.specifier==6 or a2.specifier==7)):      
	    a.specifier=a2.specifier	          
      elif((a1.specifier==6 or a1.specifier==7) and (a2.specifier==4 or a2.specifier==5)):      
	    a.specifier=a1.specifier	          
      a.type=a.specifier*100
      return a

def initAttr(dest):
#      print "\nInside initAttr(dest) Method\n"
      #dest->Type[0]='\0'; 
      #i=0
      dest.id=None
      dest.type=0	
      dest.isArray=0		# True if variable is array
      dest.ArrayLimit=0	#upper limit of array (valid if DIMENSION is true)
      dest.width=0
      #dest.isptrConst=0
      dest.isPointer=0
      dest.qualifier=0
      dest.specifier=0
      dest.storage=0
      dest.scope=0
      dest.IntConstValue=0		# because this g++ compiler set 4 byte for long but we are setting 8 bytes
      dest.IntConst=0
      dest.FloatConstValue=0			# to store the value of double or float
      dest.StringValue=None
      dest.isString=0
      dest.code=None	#For intermediate code generation	 
      dest.icode=None
      dest.offset=0			#0 means not
      dest.numParameters=0
      #dest.isdoubleptr=0
      dest.isFunction=0
      for i in range(MaxPar):      
	    dest.ParameterList[i]=None
      #return dest
      #class_definition=0
#	set_temp 0
      return dest

def PassSymEntry(a1):
      print "\nInside PassSymEntry Function\n"      
      a = Attribute()      
      #print "Error Check: "+a1.id
      if(a1.id!=None):
	    #print "Error Check: a.id = a1.id"
	    a.id = a1.id	         
      else:      
	    a.id=None      
      a.type=a1.type
      a.isArray=a1.isArray
      a.ArrayLimit=a1.ArrayLimit
      a.isPointer=a1.isPointer
      a.scope=a1.scope
      a.isFunction=a1.isFunction
      a.isString=0
      a.offset=a1.offset
      a.numParameters=a1.numParameters
      a.code=None
      a.icode=None
      a.StringValue=None
      a.IntConstValue=0		
      a.IntConst=0
      a.specifier=0
      a.qualifier=0
      a.storage=0
      a.FloatConstValue=0
      #ParameterList
      for i in range(MaxPar):
	    if(a1.ParameterList[i]==None):      
		  break      
	    a.ParameterList[i]=a1.ParameterList[i]    	    
      #print "Error Check: "+a.id
      return a      

def PassAttribute(a1):      
      print "\n Inside PassAttribute Method\n"
      i = 0
      a = Attribute()
      if a1.id != None:
	    a.id = a1.id
      else:
	    a.id = None
      
      a.type=a1.type
      a.isArray=a1.isArray
      a.ArrayLimit=a1.ArrayLimit
      a.width=a1.width
      a.isPointer=a1.isPointer
      a.qualifier=a1.qualifier
      a.specifier=a1.specifier
      a.storage=a1.storage
      a.scope=a1.scope
      a.IntConstValue=a1.IntConstValue
      a.IntConst=a1.IntConst
      a.FloatConstValue=a1.FloatConstValue
      a.isFunction=a1.isFunction
      a.isString=a1.isString
      a.offset=a1.offset
      a.numParameters=a1.numParameters
      if a1.StringValue != None:
	    a.StringValue = a1.StringValue
      else:
	    a.StringValue = None
      if ( a1.code != None ) and ( a1.icode != "" ):
	    a.code = a1.code
      else:
	    a.code = ""
      if (a1.icode != None) and (a1.icode != ""):
	    a.icode = a1.icode
      else:
	    a.icode = ""
      
      #ParameterList      
      for i in range(a1.numParameters):
	    if a1.ParameterList[i] == None:
		  break
	    a.ParameterList[i] = PassAttribute(a1.ParameterList[i])
      return a



def PopSym(FuncName):
      global global1
      global tail
      #temp = SymTableNode()
      temp=global1[FuncName]
      while temp.next.next != None:
	    temp = temp.next
      temp.next = None
      #free(tail[FuncName])
      tail[FuncName]=temp
   
def getNewTemp():
      global num_temporaries
      #Returns a new temporary named _T<num>
      temp = "_T00"
      temp1 = "_T"
      #temp2 = str(num_temporaries / 10) + '0'
      #temp3 = str(num_temporaries % 10) + '0'

      temp2 = str(num_temporaries / 10)
      temp3 = str(num_temporaries % 10)
      temp = temp1 + temp2 + temp3
      num_temporaries = num_temporaries + 1
      return temp
'''      
      num_temporaries=num_temporaries+1
      return "$labeltemp%d" % num_temporaries   
'''
      
def getNewLabel():
      global num_labels
      #Returns a new temporary named _T<num>      
      temp = "_L00"
      temp1 = "_L"
      #temp2 = str(num_labels / 10) + '0'      
      #temp3 = str(num_labels % 10) + '0'

      temp2 = str(num_labels / 10)
      temp3 = str(num_labels % 10)
      temp = temp1 + temp2 + temp3
      num_labels = num_labels + 1
      return temp
'''
      num_labels=num_labels+1
      return "$label%d" % num_labels
'''

def replicate(str1):
      if str1!= None:
	    temp = str1
      else:
	    temp = ""
      #free(str1);
      return temp
      
      
def append(str1, str2):
	return str1 + str2


def gen(instr, reg, addr):
      buf = addr
      t = instr + " " + reg + "," + buf
      return t

def toAddr(offset):
      global num_labels      
      if offset < 100 :
	    temp = "---($sp)"
	    #offset = - offset;
	    # again 'str' object does not support item assignment
	    #temp[1] = str(offset / 10) + '0'
	    #temp[2] = str(offset % 10) + '0'
	    #temp1 = str(offset / 10) + '0'
	    #temp2 = str(offset % 10) + '0'

	    #temp1 = str(num_labels / 10)      
	    #temp2 = str(num_labels % 10)
	    #temp = "-"+temp1+temp2+"($sp)"

	    temp1 = str(offset/ 10)      
	    temp2 = str(offset% 10)
	    temp = "-"+temp1+temp2+"($sp)"
	    
	    return temp
      else:
	    temp = "----($sp)"
	    #offset = - offset;
	    #temp[1] = (offset / 100) + '0'
	    #temp[2] = ((offset % 100) / 10) + '0'
	    #temp[3] = (offset % 10) + '0'

	    temp1 = str(offset / 100)
	    temp2 = str((offset % 100) / 10)
	    temp3 = str(offset % 10)
	    return "-"+ temp1 + temp2 + temp3 + "($sp)"

      
